package utils

import (
	"errors"
	"fmt"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"os"
	"regexp"
	"strconv"
	"time"
	"whitelist/model"
)

// ImportEmails 从excel导入emails
func ImportEmails(filePath string, ip string) error {
	_, err := os.Stat(filePath)
	if err != nil {
		return errors.New("file not found")
	}
	f, openErr := excelize.OpenFile(filePath)
	if openErr != nil {
		return openErr
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()
	rows, exlErr := f.GetRows("Sheet1")
	if exlErr != nil {
		return exlErr
	}
	emailRegexp := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
	var emails []model.WaitList
	for rIndex, row := range rows {
		if !emailRegexp.MatchString(row[0]) {
			return errors.New("The email in line " + strconv.Itoa(rIndex+1) + " is incorrect")
		}
		emails = append(emails, model.WaitList{
			Email:         row[0],
			Code:          "",
			Referral:      0,
			IP:            ip,
			WhiteListFlag: true,
			RegisterFlag:  false,
			Unsubscribe:   true,
		})
	}
	db := GetDB()
	result := db.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "email"}},
		DoUpdates: clause.AssignmentColumns([]string{"white_list_flag"}),
	}).Create(&emails)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

// BatchGrant 批量发放token
func BatchGrant(filePath string) error {
	_, err := os.Stat(filePath)
	if err != nil {
		return errors.New("file not found")
	}
	f, openErr := excelize.OpenFile(filePath)
	if openErr != nil {
		return openErr
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()
	rows, exlErr := f.GetRows("Sheet1")
	if exlErr != nil {
		return exlErr
	}
	emailRegexp := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
	upByEmail := make(map[string]uint64)
	var emails []string
	for rIndex, row := range rows {
		token, err := strconv.ParseUint(row[1], 10, 64)
		if err != nil {
			return errors.New(fmt.Sprintf("The token in line %d is incorrect", rIndex+1))
		}
		if row[0] != "" {
			if !emailRegexp.MatchString(row[0]) {
				return errors.New(fmt.Sprintf("The email in line %d is incorrect", rIndex+1))
			}
			upByEmail[row[0]] = token
			emails = append(emails, row[0])
		}
	}
	db := GetDB()
	var accounts []model.Account
	handle := db.Model(&model.Account{})
	if len(emails) > 0 {
		handle = handle.Where(map[string]interface{}{"email": emails})
	}
	result := handle.Find(&accounts)
	if result.Error != nil {
		return errors.New("an error occurred while searching for users")
	}
	var grants []model.TokenGrants
	type UpdateTokens struct {
		Id         uint
		TokenCount uint64
	}
	var updates []model.Account
	var incr uint64
	for _, value := range accounts {
		if t, ok := upByEmail[value.Email]; ok {
			incr = t
		}
		if incr > 0 {
			value.TokenCount = value.TokenCount + incr
			updates = append(updates, value)
			grants = append(grants, model.TokenGrants{
				AccountId: value.ID,
				Date:      time.Now().Format(time.DateOnly),
				Token:     incr,
				Way:       2,
			})
		}
		incr = 0
	}
	if len(grants) <= 0 {
		return errors.New("some errors resulted in no data updates")
	}

	return db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&grants).Error; err != nil {
			return err
		}
		for _, u := range updates {
			if err := tx.Model(&model.Account{}).Where("id = ?", u.ID).Update("token_count", u.TokenCount).Error; err != nil {
				return err
			}
		}
		return nil
	})

}
